from markdown import markdown_transform
from markdown.common import get_guid_id, get_ordering_id
from markdown.parser import *
from markdown.template import (get_api_item_template, get_json_res_template,
                               get_success_res_example)

"""
Author: Gaoqiang Du
Description：apifox文档模型
Time: 2022/4/16 23:54
"""


class ApiDoc(object):
    check_line = None

    def __init__(self, title="", description="", req_method="GET",
                 path="/", req_headers=None, req_params=None,
                 req_body=None, res_json=None, res_exm="", data_mod=None):
        self.title = title
        self.description = description
        self.req_method = req_method
        self.path = path
        self.req_headers = req_headers or {}
        self.req_params = req_params or {}
        self.req_body = req_body or {}
        self.res_json = res_json or {}
        self.res_example = res_exm
        self.data_mod = data_mod or {}
        self.pipeline = self.get_pipeline()

    @staticmethod
    def get_pipeline():
        """获取markdown元素解析容器字典"""
        return {
            "title": {"func": get_title, "next": "description"},
            "description": {"func": find_description},
            "req_method": {"func": find_req_method},
            "req_params": {"func": find_req_params},
            "res_json": {"func": find_res_params},
            "res_example": {"func": find_res_example},
        }

    def parser_markdown(self):
        """解析markdown文件（用于转换为apifox文件）"""
        check = check_line()
        next(check)
        key, info = "title", self.pipeline.pop("title")
        action = info["func"]()
        next(action)
        line = ""
        while 1:
            if action:
                try:
                    status, data = action.send(line)
                    setattr(self, key, data)
                    if status:
                        raise Exception("该流程已结束。")
                except:
                    key = info.get("next") or check.send(line)
                    info = self.pipeline.pop(key, {})
                    action = info.get("func")
                    if action:
                        action = action()
                        next(action)
                        action.send(line)
            else:
                key = check.send(line)
                info = self.pipeline.pop(key, {})
                action = info.get("func")
                if action:
                    action = action()
                    next(action)
                    action.send(line)

            line = yield len(self.pipeline) + (1 if action else 0)

    def format_to_template(self):
        """将对象数据转换成apifox文件"""
        api_json = get_api_item_template()
        api_json["api"]["ordering"] = get_ordering_id()
        api_json["name"] = self.title
        api_json["api"]["description"] = self.description
        api_json["api"]["method"] = self.req_method
        api_json["api"]["id"] = get_guid_id()
        api_json["api"]["parameters"]["query"] = self.req_params
        api_json["api"]["responses"].append(self.format_res_temp())
        if self.res_example:
            api_json["api"]["responseExamples"].append(
                get_success_res_example(self.res_example))

        return api_json

    def format_res_temp(self):
        """将相应数据转换成apifox元素"""
        res_temp = get_json_res_template()
        for item in self.res_json:
            key = item.pop("name", None)
            if key:
                res_temp["jsonSchema"]["properties"][key] = item
                res_temp["jsonSchema"]["required"].append(key)

        return res_temp

    def format_to_markdown(self):
        """将对象反转为markdown数据"""
        markdown_list = []
        markdown_list.append(
            markdown_transform.title_transform(self.title))
        markdown_list.append(
            markdown_transform.description_transform(self.description))
        markdown_list.append(
            markdown_transform.req_method_transform(self.req_method))

        if self.req_params:
            param_table = [["名称", "类型", "是否必需", "示例值", "描述"]]
            for i in self.req_params:
                param_table.append(
                    [i["name"], i.get("type", "string"),
                     i["required"], i.get("sampleValue"), i["description"]])
            markdown_list.append(
                markdown_transform.get_req_params_md() +
                markdown_transform.table_transform(param_table)
            )

        markdown_list.append(self.res_json_to_markdown())

        markdown_list.append(
            markdown_transform.res_example_transform(self.res_example))

        return "\n".join([i for i in markdown_list if i])

    def res_json_to_markdown(self):
        """将相应参数转换成markdown的table"""
        if not self.res_json:
            return ""

        param_table = [["名称", "类型", "描述"]]
        self.res_to_markdown(param_table, self.res_json)

        return (
                markdown_transform.get_res_params_md() +
                markdown_transform.table_transform(param_table)
        )

    def res_to_markdown(self, param_table: List[List[str]], res_json, pre_key=""):
        if isinstance(res_json, list):
            for i in res_json:
                param_table.append(
                    [i["name"], i["type"], i["description"]])

        elif isinstance(res_json, dict):
            for k, v in res_json.items():

                # 预处理引用数据模型
                if v.get("$ref"):
                    v = {
                        "type": "object",
                        "properties": self.data_mod.get(v.get("$ref"))
                    }

                # 添加该记录
                param_table.append([pre_key + k, v["type"], v.get("description", "")])
                # 处理容器类型
                if v["type"] in ["array", "object"]:
                    # 优化数据字段展示
                    if v["type"] == "array":
                        properties = v.get("items", {}).get("properties", {})
                        properties = properties or self.data_mod.get(
                            v.get("items", {}).get("$ref", ""))
                        new_pre_key = pre_key + k + "[i]."
                    else:
                        properties = v.get("properties", {})
                        new_pre_key = pre_key + k + "."

                    self.res_to_markdown(param_table, properties, new_pre_key)


class DataModel(object):
    """
    主要作为apifox的数据类型数据提取类
    """

    def __init__(self):
        self.source_data = {}

    def from_apifox(self, data_list):
        for i in data_list:
            if i.get("id") and i.get("schema"):
                # 存储数据模型
                properties = i.get("schema").get("jsonSchema", {}
                                                 ).get("properties", {})
                self.source_data[i.get("id")] = properties
            else:
                # 处理分组情况
                self.from_apifox(i.get("items", []))

    def get(self, key, default=None):
        return self.source_data.get(key, default)
